package com.im;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.List;

// 结果码
enum ResultCode {
    ADD_FRIEND_ALLOW,               // "添加%s为好友成功。"
    ADD_FRIEND_NOT_ALLOW,           // "拒绝和你成为好友。"
    ALREADY_BE_FRIENDS,             // "已经是你的好友了。"
    FRIEND_NAME_EQUAL_SELF_NAME,    // "好友名字与自己名字相同。"
    LOGON_SUCCEEDED,                // "登录成功。"
    NETWORK_ERROR,                  // "连接服务失败，请参考使用说明。"
    PASSWORD_WRONG,                 // "密码不正确。"
    REG_SUCCEEDED,                  // "注册成功。"
    SUCCEEDED,                      // ""
    TOO_MANY_FRIENDS,               // "朋友太多了，不能再继续添加了。"
    USER_ALREADY_LOGON,             // "该用户已经登录了。"
    USER_EXISTS,                    // "该用户名已经被注册了。"
    USER_NOT_FOUND                  // "该用户尚未注册。"
}

// 协议
abstract class ImProtocol implements Serializable {
    // 类型
    public enum Type {
        ADD_FRIEND_REQUEST, // 添加好友请求
        ADD_FRIEND_RESULT,  // 添加好友结果
        CHAT,               // 聊天
        FRIEND_LOGON,       // 好友登录
        LOGOFF,             // 离线
        LOGON,              // 登录
        REG                 // 注册
    }

    public static final String MULTI_CHAT = "群发消息";      // 群发消息标志
    public static final String SERVER_IP = "192.168.3.8";   // 服务器 IP 地址
    public static final int SERVER_PORT = 5000;             // 服务器端口号
    protected final Type mType;                             // 协议类型

    /**
     * 构造方法。
     * @param type  协议类型
     */
    public ImProtocol(Type type) {
        mType = type;
    }

    /**
     * 将数据报包转换成协议。
     * @param data  数据报包
     * @return 协议
     */
    public static ImProtocol fromDatagramPacket(DatagramPacket data) {
        ImProtocol pro = null;
        try {
            final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data.getData());
            final ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            pro = (ImProtocol)objectInputStream.readObject();
            objectInputStream.close();
            byteArrayInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pro;
    }

    /**
     * 将协议转换成数据报包。
     * @param pro   协议
     * @param ip    目标 ip 地址
     * @param port  目标端口号
     * @return 数据报包
     */
    public static DatagramPacket toDatagramPacket(ImProtocol pro, InetAddress ip, int port) {
        byte[] bytes;
        try {
            final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            final ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(pro);
            bytes = byteArrayOutputStream.toByteArray();
            objectOutputStream.close();
            byteArrayOutputStream.close();
            return new DatagramPacket(bytes, bytes.length, ip, port);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

// 添加好友请求
class AddFriendRequest extends ImProtocol {
    public final String mDstUsername;   // 目标用户名
    public final int mSrcIconIndex;     // 源用户头像索引
    public final String mSrcUsername;   // 源用户名

    /**
     * 构造方法。
     * @param dstUsername   目标用户名
     * @param srcIconIndex  源用户头像索引
     * @param srcUsername   源用户名
     */
    public AddFriendRequest(String dstUsername, int srcIconIndex, String srcUsername) {
        super(Type.ADD_FRIEND_REQUEST);
        mDstUsername = dstUsername;
        mSrcIconIndex = srcIconIndex;
        mSrcUsername = srcUsername;
    }
}

// 添加好友结果
class AddFriendResult extends ImProtocol {
    public final int mDstIconIndex;         // 目标用户头像索引
    public final String mDstUsername;       // 目标用户名
    public final ResultCode mResultCode;    // 结果码
    public final String mSrcUsername;       // 源用户名

    /**
     * 构造方法。
     * @param dstIconIndex  目标用户头像索引
     * @param dstUsername   目标用户名
     * @param resultCode    结果码
     * @param srcUsername   源用户名
     */
    public AddFriendResult(int dstIconIndex, String dstUsername, ResultCode resultCode, String srcUsername) {
        super(Type.ADD_FRIEND_RESULT);
        mDstIconIndex = dstIconIndex;
        mDstUsername = dstUsername;
        mResultCode = resultCode;
        mSrcUsername = srcUsername;
    }
}

// 聊天信息
class ChatInfo extends ImProtocol {
    public final String mContent;       // 内容
    public final String mDstUsername;   // 目标用户名
    public final int mSrcIconIndex;     // 源用户头像索引
    public final String mSrcUsername;   // 源用户名
    public final String mTime;          // 生成时间

    /**
     * 构造方法。
     * @param content       内容
     * @param dstUsername   目标用户名
     * @param srcIconIndex  源用户头像索引
     * @param srcUsername   源用户名
     * @param time          生成时间
     */
    public ChatInfo(String content, String dstUsername, int srcIconIndex, String srcUsername, String time) {
        super(Type.CHAT);
        mContent = content;
        mDstUsername = dstUsername;
        mSrcIconIndex = srcIconIndex;
        mSrcUsername = srcUsername;
        mTime = time;
    }
}

// 好友登录通知
class FriendLogon extends ImProtocol {
    public final String mUsername;  // 用户名

    /**
     * 构造方法。
     * @param username  用户名
     */
    public FriendLogon(String username) {
        super(Type.FRIEND_LOGON);
        mUsername = username;
    }
}

// 离线请求
class LogoffRequest extends ImProtocol {
    public final String mUsername;  // 用户名

    /**
     * 构造方法。
     * @param username  用户名
     */
    public LogoffRequest(String username) {
        super(Type.LOGOFF);
        mUsername = username;
    }
}

// 登录请求
class LogonRequest extends ImProtocol {
    public final UserInfo mUserInfo;    // 用户信息

    /**
     * 构造方法。
     * @param password  密码
     * @param username  用户名
     */
    public LogonRequest(String password, String username) {
        super(Type.LOGON);
        mUserInfo = new UserInfo(0, password, username);
    }
}

// 登录结果
class LogonResult extends ImProtocol {
    public int mFriendCount;                // 好友数
    public List<UserInfo> mFriends;         // 好友名列表
    public List<Boolean> mFriendsOnline;    // 好友在线状态列表
    public int mIconIndex;                  // 头像索引
    public ResultCode mResultCode;          // 结果码

    /**
     * 构造方法。
     */
    public LogonResult() {
        super(Type.LOGON);
        mFriendCount = 0;
        mIconIndex = -1;
        mResultCode = ResultCode.SUCCEEDED;
    }
}

// 注册请求
class RegRequest extends ImProtocol {
    public final UserInfo mUserInfo;    // 用户信息

    /**
     * 构造方法。
     * @param iconIndex 头像索引
     * @param password  密码
     * @param username  用户名
     */
    public RegRequest(int iconIndex, String password, String username) {
        super(Type.REG);
        mUserInfo = new UserInfo(iconIndex, password, username);
    }
}

// 注册结果
class RegResult extends ImProtocol {
    public ResultCode mResultCode;  // 结果码

    /**
     * 构造方法。
     */
    public RegResult() {
        super(Type.REG);
        mResultCode = ResultCode.SUCCEEDED;
    }
}

// 用户信息
class UserInfo implements Serializable {
    public final int mIconIndex;    // 头像索引
    public final String mPassword;  // 密码
    public final String mUsername;  // 用户名

    /**
     * 构造方法。
     * @param iconIndex 头像索引
     * @param password  密码
     * @param username  用户名
     */
    public UserInfo(int iconIndex, String password, String username) {
        mIconIndex = iconIndex;
        mPassword = password;
        mUsername = username;
    }
}
